package Classes.Components
{
	import Classes.Entity;
	import Classes.GameEvent;
	import Classes.World;
	
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.utils.getQualifiedClassName;

	public class RigidBodyComponent extends BaseComponent
	{
		private var m_display:Sprite = new Sprite();		

		private var m_size:Number = 0;
		private var m_speed:Number = 1;
		private var x:Number = 0;
		private var y:Number = 0;
		private var destX:Number = 0;
		private var destY:Number = 0;
		
		private var m_vel:Point = new Point(0,0);
		private var m_accel:Point = new Point(0,0);
		
		private var m_isMoving:Boolean = false;
		private var m_lastPosition:Point = new Point(0,0);
		
		private var m_currentDirection:Point;
		private var m_currentStopWithin:Number = 0;
		
		public function RigidBodyComponent(entity:Entity)
		{
			super(entity);
			m_size = getConfig().attributes['size'];
			m_speed = getConfig().attributes['speed'];
		}
		
		public function isMoving():Boolean{
			return m_isMoving;
		}
		
		public function getConfig():Object{
			return m_entity.config.children.rigidBody[0];
		}
		
		public function getSize():Number{
			return m_size;
		}
		
		public function detectCollisionWithPoint(point:Point):Boolean{
			var distFromPoint:Number = point.subtract(getPosition()).length;
			return distFromPoint <= m_size;
		}
		
		public function setSpeed(speed:Number):void{
			m_speed = speed;
		}
		
		public function getPosition():Point{
			return new Point(x,y);
		}
		
		public function setPosition(pos:Point):void{
			x = pos.x;
			y = pos.y;
		}
		
		public function setDestination(pos:Point):void{
			destX = pos.x;
			destY = pos.y;
		}
		
		public function getDestination():Point{
			if(m_currentStopWithin){
				var direction:Point = new Point(destX,destY).subtract(getPosition());
				direction.normalize(m_currentStopWithin);
				
				return new Point(destX,destY).subtract(direction);
			} else {
				return new Point(destX,destY);	
			}
			
		}

		public function attach(world:World):void{
			m_entity.setWorld(world);
			world.attach(m_entity);
			world.getDisplay().addChild(m_display);
		}		
		
		public function getDisplay():Sprite{
			return m_display;
		}
		
		public function forceUpdate():void{
			m_display.x = x * Main.P2WSCALE;
			m_display.y = y * Main.P2WSCALE;			
		}

		override public function update(delta:int):void{
			var display:Sprite = m_display;
			var nextPosition:Point;
			var deltaSeconds:Number = delta/1000;
			
			if(m_isMoving){
				nextPosition = new Point(x + m_currentDirection.x*deltaSeconds*m_speed,y + m_currentDirection.y*deltaSeconds*m_speed);
				if(hasPassedDestination(nextPosition)){
					m_isMoving = false;
					setPosition(getDestination());
					m_entity.dispatchEvent(new GameEvent(GameEvent.DESTINATION_REACHED));
				}else {
					setPosition(nextPosition);
				}
				
				display.x = x * Main.P2WSCALE;
				display.y = y * Main.P2WSCALE;
			} 
		}
		
		private function hasPassedDestination(nextPosition:Point):Boolean{
			var nextDistance:Number = nextPosition.subtract(getPosition()).length;
			var destDistance:Number = getDestination().subtract(getPosition()).length;
			
			var hasPassed:Boolean = (destDistance <= nextDistance);
			return hasPassed;
		}
		
		public function moveTo(point:Point, stopWithin:Number=0):void{
			m_isMoving = true;
			m_currentStopWithin = stopWithin;
			setDestination(point);
			m_currentDirection = getDestination().subtract(getPosition());
			m_currentDirection.normalize(1);
		}

		override public function destroy():void{
			getDisplay().parent.removeChild(getDisplay());
			getWorld().detach(m_entity);
			super.destroy();		
		}
		
		public function getMobsInRadius(radius:Number):Vector.<Entity>{
			var mobs:Vector.<Entity> = new Vector.<Entity>;
			for each(var mob:Entity in getWorld().getAttachedMobs()){
				var mobDistance:Number = getPosition().subtract(mob.getRigidBodyComponent().getPosition()).length;
				if(mobDistance <= radius){
					mobs.push(mob);
				}
			}
			
			return mobs;
		}
		
		public function getPlayersInRadius(radius:Number):Vector.<Entity>{
			var players:Vector.<Entity> = new Vector.<Entity>;
			for each(var player:Entity in getWorld().getAttachedPlayers()){
				var playerDistance:Number = getPosition().subtract(player.getRigidBodyComponent().getPosition()).length;
				if(playerDistance <= radius){
					players.push(player);
				}
			}
			
			return players;			
		}
	}
}